package com.calvin.android;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;

public class EventDispatch {
	public enum CListen {
		INIT, CLICK, LONGCLICK, ITEMCLICK, ITEMLONGCLICK
	}

	private static EventDispatch mShared = null;
	private Map<View, Map<CListen, Object[]>> mEventMap;
	private EventDispatchListener mListener = new EventDispatchListener();

	private EventDispatch() {
		mEventMap = new HashMap<View, Map<CListen, Object[]>>();
	}

	public static EventDispatch shared() {
		return null == mShared ? (mShared = new EventDispatch()) : mShared;
	}

	public void put(View view, CListen event, Object target, String method) {
		if (null != view && null != target && null != method) {
			switch (event) {
			case INIT:
				EventDispatch.invokeMethod(target, method, View.class, view);
				return;
			case CLICK:
				view.setOnClickListener(mListener);
				break;
			case LONGCLICK:
				view.setOnLongClickListener(mListener);
				break;
			case ITEMCLICK:
				if (view instanceof AdapterView) {
					((AdapterView<?>) view).setOnItemClickListener(mListener);
				}
				break;
			case ITEMLONGCLICK:
				if (view instanceof AdapterView) {
					((AdapterView<?>) view).setOnLongClickListener(mListener);
				}
				break;
			default:
				break;
			}
			if (!mEventMap.containsKey(view)) {
				mEventMap.put(view, new HashMap<CListen, Object[]>());
			}
			mEventMap.get(view).put(event, new Object[] { target, method });
		}
	}

	public static Object invokeMethod(Object target, String method, Object... argv) {
		if (null != target && null != method && argv.length % 2 == 0) {
			Class<?>[] paramsTypes = new Class[argv.length / 2];
			Object[] params = new Object[argv.length / 2];
			for (int i = 0; i < argv.length / 2; i++) {
				paramsTypes[i] = (Class<?>) argv[i * 2];
				params[i] = argv[i * 2 + 1];
			}
			try {
				Method invokeMethod = target.getClass().getMethod(method, paramsTypes);
				if (null != invokeMethod) {
					return invokeMethod.invoke(target, params);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	class EventDispatchListener implements OnClickListener, OnLongClickListener, OnItemClickListener, OnItemLongClickListener {
		@Override
		public void onClick(View v) {
			Object[] objs = mEventMap.get(v).get(CListen.CLICK);
			EventDispatch.invokeMethod(objs[0], objs[1].toString(), View.class, v);
		}

		@Override
		public boolean onLongClick(View v) {
			Object[] objs = mEventMap.get(v).get(CListen.LONGCLICK);
			return (Boolean) EventDispatch.invokeMethod(objs[0], objs[1].toString(), View.class, v);
		}

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			Object[] objs = mEventMap.get(parent).get(CListen.ITEMCLICK);
			EventDispatch.invokeMethod(objs[0], objs[1].toString(), AdapterView.class, parent, View.class, view, int.class, position, long.class, id);
		}

		@Override
		public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
			Object[] objs = mEventMap.get(parent).get(CListen.ITEMLONGCLICK);
			return (Boolean) EventDispatch.invokeMethod(objs[0], objs[1].toString(), AdapterView.class, parent, View.class, view, int.class, position, long.class, id);
		}

	}

}
